#ifndef  __VECTOR3F_H__
#define  __VECTOR3F_H__

#include <math.h>

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define FABS_MIN_DIFF 0.00001

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template <class t> struct Vec3 {
	union {
		struct {t x,y,z;};
		struct {t r,g,b;};
		t raw[3];
	};

	Vec3(){}
	Vec3(const t * p) : x(p[0]), y(p[1]), z(p[2]) {}
	Vec3(t _x, t _y, t _z) : x(_x),y(_y),z(_z) {}

	Vec3<t>& operator =(const Vec3<t>& s) { if(this != &s) { x=s.x; y=s.y; z=s.z; } return *this; }
	const Vec3<t>& operator *= (t f) { x*=f; y*=f; z*=f; return *this; }
	const Vec3<t>& operator /= (t f) { x/=f; y/=f; z/=f; return *this; }

	const Vec3<t>& operator += (const Vec3<t> &v) { x+=v.x; y+=v.y; z+=v.z; return *this; }
	const Vec3<t>& operator -= (const Vec3<t> &v) { x-=v.x; y-=v.y; z-=v.z; return *this; }

	Vec3<t> operator /  (t f)              const { return Vec3<t>(x/f, y/f, z/f); }
	Vec3<t> operator - () { return Vec3(-x, -y, -z); }
	inline Vec3<t> operator * (t f)              const { return Vec3<t>(x*f, y*f, z*f); }
	inline Vec3<t> operator ^ (const Vec3<t> &v) const { return Vec3<t>(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x); }
	inline Vec3<t> operator + (const Vec3<t> &v) const { return Vec3<t>(x+v.x, y+v.y, z+v.z); }
	inline Vec3<t> operator - (const Vec3<t> &v) const { return Vec3<t>(x-v.x, y-v.y, z-v.z); }

	bool operator == (const Vec3<t> &v) const { return x==v.x && y==v.y && z==v.z; }
	bool operator != (const Vec3<t> &v) const { return x!=v.x || y!=v.y || z!=v.z; }

	inline t operator *  (const Vec3<t> &v) const { return x*v.x + y*v.y + z*v.z; }
	inline operator       t * ()       { return raw; }
	inline operator const t * () const { return raw; }

	t norm ()    const { return sqrt(x*x+y*y+z*z); }
	t norm2 ()    const { return x*x+y*y+z*z; }

	t cosangle (Vec3<t> &v) {
		t prod = v.norm()*norm();
		if (prod>FABS_MIN_DIFF)
			return ((x*v.x + y*v.y + z*v.z)/(prod));
		else
			return 100000.0;
	}

	void normalize(t l=1) { *this *= l/norm(); }
};

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

typedef Vec3<float>  Vector3f;

#endif // __VECTOR3F_H__
